----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    18:08:59 09/17/2014 
-- Design Name: 
-- Module Name:    OFDM_Tx - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity OFDM_Tx is
    Port ( clk : in  STD_LOGIC;
           ce : in  STD_LOGIC;
           rst : in  STD_LOGIC;
			  dataIn : in  STD_LOGIC_VECTOR (5 downto 0);
			  dataAvailable_in : in  STD_LOGIC;
			  dataInReady : out STD_LOGIC;
           I : out  STD_LOGIC_VECTOR (15 downto 0);
           Q : out  STD_LOGIC_VECTOR (15 downto 0));
end OFDM_Tx;

architecture Behavioral of OFDM_Tx is

----------------------------------------------------components------------------------------------------

component ConstellationMap_Tx is
    Port ( clk : in  STD_LOGIC;
           ce : in  STD_LOGIC;
			  rst : in STD_LOGIC;
           modType : in  STD_LOGIC_VECTOR (2 downto 0);
           dataIn : in  STD_LOGIC_VECTOR (5 downto 0);
			  dataAvailable_in :  in  STD_LOGIC;
           dataOut_R : out  STD_LOGIC_VECTOR (3 downto 0);
           dataOut_I : out  STD_LOGIC_VECTOR (3 downto 0);
			  dataAvailable_out :  out  STD_LOGIC 
	 );
end component ConstellationMap_Tx;

component Hermitian_conj is
    Port ( clk : in  STD_LOGIC;
           ce : in  STD_LOGIC;
           SymIn : in  STD_LOGIC_VECTOR (7 downto 0);
           dataAvailable_in : in  STD_LOGIC;
           SymOut : out  STD_LOGIC_VECTOR (7 downto 0);
           dataAvailable_out : out  STD_LOGIC;
			  outDataLast : out  STD_LOGIC;
           dataInReady : out  STD_LOGIC
	 );
end component Hermitian_conj;

component xfft_v8_0
  port (
    aclk : in STD_LOGIC := 'X'; 
    aclken : in STD_LOGIC := 'X'; 
    s_axis_config_tvalid : in STD_LOGIC := 'X'; 
    s_axis_data_tvalid : in STD_LOGIC := 'X'; 
    s_axis_data_tlast : in STD_LOGIC := 'X'; 
    s_axis_config_tready : out STD_LOGIC; 
    s_axis_data_tready : out STD_LOGIC; 
    m_axis_data_tvalid : out STD_LOGIC; 
    m_axis_data_tlast : out STD_LOGIC; 
    event_frame_started : out STD_LOGIC; 
    event_tlast_unexpected : out STD_LOGIC; 
    event_tlast_missing : out STD_LOGIC; 
    event_data_in_channel_halt : out STD_LOGIC; 
    s_axis_config_tdata : in STD_LOGIC_VECTOR ( 15 downto 0 ); 
    s_axis_data_tdata : in STD_LOGIC_VECTOR ( 47 downto 0 ); 
    m_axis_data_tdata : out STD_LOGIC_VECTOR ( 63 downto 0 ) 
  );
end component;

----------------------------------------------------signals----------------------------------------------

signal sig_DataInReady : std_logic := '0';

signal sig_modType : STD_LOGIC_VECTOR(2 DOWNTO 0) := "101";
signal sig_const_symR_out  : STD_LOGIC_VECTOR(3 DOWNTO 0) := (others => '0');
signal sig_const_symI_out  : STD_LOGIC_VECTOR(3 DOWNTO 0) := (others => '0');
signal sig_dataAvailable_out_const : STD_LOGIC := '0'; 
	 
signal sig_HermitianDataInReady : STD_LOGIC := '0';
signal sig_HermitianDataOutAvail : STD_LOGIC := '0';
signal sig_HermitianOutDataLast : STD_LOGIC := '0';
signal sig_HermitianDataOut : STD_LOGIC_VECTOR(7 DOWNTO 0) := (others => '0');

signal sig_IFFT_config_FwInv : STD_LOGIC := '0';
signal sig_IFFT_config_cpLen : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"40";
signal sig_IFFT_config_tdata	: STD_LOGIC_VECTOR(15 DOWNTO 0) := (others => '0');
signal sig_IFFT_config_tvalid : STD_LOGIC := '0'; 
signal sig_IFFT_config_tready : STD_LOGIC := '0';
signal sig_IFFT_InData_tdata  : STD_LOGIC_VECTOR(47 DOWNTO 0) := (others => '0');
signal sig_IFFT_InData_tvalid : STD_LOGIC := '0';
signal sig_IFFT_InData_tlast  : STD_LOGIC := '0';
signal sig_IFFT_InData_tready : STD_LOGIC := '0';

signal sig_OutData_tdata		: STD_LOGIC_VECTOR(63 DOWNTO 0) := (others => '0');
signal sig_OutData_tvalid : STD_LOGIC := '0';
signal sig_OutData_tlast : STD_LOGIC := '0';
signal sig_IFFT_eventFrameStarted : STD_LOGIC := '0';
signal sig_IFFT_eventTlastUnexpected : STD_LOGIC := '0';
signal sig_IFFT_eventTlastMissing : STD_LOGIC := '0';
signal sig_IFFT_eventDataInChannelHalt : STD_LOGIC := '0';

type sm_states is (idle, start);
signal sig_sm_states : sm_states := idle;
	 
---------------------------------------------------------------------------------------------------------

begin
						
constellation: ConstellationMap_Tx
 Port map ( 
		  clk => clk,
		  ce => ce and sig_DataInReady,
		  rst => '0',
		  modType => sig_modType,
		  dataIn => dataIn,
		  dataAvailable_in => dataAvailable_in,
		  dataOut_R => sig_const_symR_out,
		  dataOut_I => sig_const_symI_out, 
		  dataAvailable_out => sig_dataAvailable_out_const		  
 );
  
HermitianConj: Hermitian_conj  
 Port map ( 
        clk => clk,
		  ce => ce and sig_IFFT_InData_tready,
		  SymIn => sig_const_symR_out & sig_const_symI_out,
		  dataAvailable_in => sig_dataAvailable_out_const,
		  SymOut => sig_HermitianDataOut,
		  dataAvailable_out => sig_HermitianDataOutAvail,
		  outDataLast => sig_HermitianOutDataLast,
		  dataInReady => sig_HermitianDataInReady
 ); 

IFFT : xfft_v8_0
port map (
	 aclk   => clk,
	 aclken   => ce,
	 s_axis_config_tvalid   => sig_IFFT_config_tvalid,
	 s_axis_data_tvalid   => sig_IFFT_InData_tvalid, 
	 s_axis_data_tlast   => sig_IFFT_InData_tlast, 
	 s_axis_config_tready   => sig_IFFT_config_tready, 
	 s_axis_data_tready   => sig_IFFT_InData_tready, 
	 m_axis_data_tvalid   => sig_OutData_tvalid, 
	 m_axis_data_tlast   => sig_OutData_tlast, 
	 event_frame_started   => sig_IFFT_eventFrameStarted, 
	 event_tlast_unexpected   => sig_IFFT_eventTlastUnexpected, 
	 event_tlast_missing   => sig_IFFT_eventTlastMissing, 
	 event_data_in_channel_halt   => sig_IFFT_eventDataInChannelHalt, 
	 s_axis_config_tdata   => sig_IFFT_config_tdata, 
	 s_axis_data_tdata   => sig_IFFT_InData_tdata, 
	 m_axis_data_tdata   => sig_OutData_tdata
);

----------------------------------------------------processes----------------------------------------------

sig_DataInReady <= sig_HermitianDataInReady and sig_IFFT_InData_tready;
dataInReady <= sig_DataInReady;

process (clk, ce, sig_IFFT_InData_tready)
begin
	if (rising_edge(clk)) then
		if (sig_HermitianDataOutAvail = '1') then
			sig_IFFT_InData_tvalid <= sig_HermitianDataOutAvail;
			sig_IFFT_InData_tdata <= "00000" & sig_HermitianDataOut(3 downto 0) & "000000000000000" & "00000" & sig_HermitianDataOut(7 downto 4) & "000000000000000";
			sig_IFFT_InData_tlast <= sig_HermitianOutDataLast;
			
			if (sig_IFFT_config_tready = '1') then
				sig_IFFT_config_tvalid <= '1';
				sig_IFFT_config_tdata <= "0000000" & sig_IFFT_config_FwInv & sig_IFFT_config_cpLen;
			else
				sig_IFFT_config_tvalid <= '0';
				sig_IFFT_config_tdata <= (others => '0');
			end if;	
		end if;
		
		if (sig_OutData_tvalid = '1') then
			I <= std_logic_vector(resize(signed(sig_OutData_tdata(59 downto 32 + 8)), 16));
			Q <= std_logic_vector(resize(signed(sig_OutData_tdata(27 downto 0 + 8)), 16));	
		else
			I <= (others=>'0');
			Q <= (others=>'0');
		end if;
	end if;	
end process;

end Behavioral;

